//
// Created by ta&to on 2022/9/28.
//
#include "tcp_connect.h"
#ifdef SOCKET_SERVER_SELECT

typedef struct tcp_socket_state_s {
    fd_set _rfds, _wfds;
};
void sFree(struct tcp_socket_event_loop_s *hset) {
    if(ISNOTNULL(hset->func_handler->data )) free(hset->func_handler->data);
    hset->func_handler->data = NULL;
}
// 初始化链接数据
void init_select(log_t *logt, struct tcp_socket_event_loop_s *hset) {
    FD_ZERO(&((struct tcp_socket_state_s *)hset->apidata)->_rfds);
    FD_SET(hset->socket_fd,&((struct tcp_socket_state_s *)hset->apidata)->_rfds);

    //超时的设定，这里也可以不需要设置时间，将这个参数设置为NULL,表明此时select为阻塞模式
    //将所有的连接全部加到这个这个集合中，可以监测客户端是否有数据到来
    for(int i = 0; i < hset->max_link; i++)
    {
        if(hset->select_fds[i]!=0)
        {
            FD_SET(hset->select_fds[i],&((struct tcp_socket_state_s *)hset->apidata)->_rfds);
        }
    }
}
int _select(log_t *logt, struct tcp_socket_event_loop_s *hset) {
    int retval = select(hset->maxfd + 1, &((struct tcp_socket_state_s *)hset->apidata)->_rfds, NULL, NULL, hset->tvp);
    if (retval == -1 && errno != EINTR) { //没有找到有效的连接 失败
        error(logt, "tcp_select.Select(): select, %s", strerror(errno));
        return -1;
    }else if(retval == 0) {          // 指定的时间到，
        debug(logt, "connnect timeout \n");
        return 0;
    }
    return retval;
}
static int __monitor_rm_fd(log_t *logt, struct tcp_socket_event_loop_s *hset, int i) {
    int fd = hset->select_fds[i];
    hset->select_fds[i]=0;
    FD_CLR(hset->select_fds[i],&((struct tcp_socket_state_s *)hset->apidata)->_rfds);
    return fd;
}
static void _offline_client(log_t *logt, struct tcp_socket_event_loop_s *hset, int fd) {
    info(logt, "A Clien is close[%d]", fd);
    close(fd);
    hset->current_link--;
}

void Close_Client(log_t *logt, struct tcp_socket_event_loop_s *hset, int fd) {
    _offline_client(logt, hset, fd);
}
void Close_link(log_t *logt, struct tcp_socket_event_loop_s *hset, int n) {
    info(logt, "A Clien is close[%d]", hset->select_fds[n]);
    close(__monitor_rm_fd(logt, hset, n));
    hset->current_link--;
}
int _select_loop(log_t *logt, struct tcp_socket_event_loop_s *hset) {   // 循环查询select容器
    for (int i = 0; i < hset->current_link; i++) {
        if(FD_ISSET(hset->select_fds[i],&((struct tcp_socket_state_s *)hset->apidata)->_rfds))
        {
            hset->current_fd = hset->select_fds[i];
            assert(hset->func_handler);
            hset->func_handler->fd = hset->select_fds[i];
            hset->func_handler->func_read(hset, __monitor_rm_fd(logt, hset, i), i);
        }
    }
}
// 链接处理 链接关闭 新建链接
int _conn_handler(log_t *logt, struct tcp_socket_event_loop_s *hset) {
    if(FD_ISSET(hset->socket_fd,&((struct tcp_socket_state_s *)hset->apidata)->_rfds))      // 是否有新连接到达
    {
        int client_fd = Accept(logt, hset->socket_fd,(struct sockaddr *)&hset->func_handler->client_addr,&hset->func_handler->sin_size);    // 当有新链接时创建链接
        if(client_fd <= 0)
        {
            error(logt, "accept error\n");
        }
        //添加新的fd 到数组中 判断有效的连接数是否小于最大的连接数，如果小于的话，就把新的连接套接字加入集合
        if(hset->current_link < hset->max_link)
        {
            for(int i = 0; i < hset->max_link; i++)
            {
                if(hset->select_fds[i]==0)
                {
                    hset->select_fds[i] = client_fd;
                    break;
                }
            }
            hset->current_link++;
            info(logt, "new connection client[%d]%s:%d\n",client_fd, inet_ntoa(hset->func_handler->client_addr.sin_addr),ntohs(hset->func_handler->client_addr.sin_port));
            hset->maxfd = client_fd > hset->maxfd ? client_fd : hset->maxfd;
        }else{
            error(logt, "max connections arrive, maxconn is %d current accept fd is %d exit\n", hset->current_link, client_fd);
            putData(logt, client_fd,"bye",4);
            CloseAll(logt, NULL, client_fd);
        }
        hset->current_fd = client_fd;
        return client_fd;
    }
}
// select d
int _init_select(log_t *logt, struct tcp_socket_event_loop_s *hset) {
    int selectfds[hset->max_link];
    hset->current_link = 0;
    struct tcp_socket_state_s state;
    hset->apidata = &state;
    (char*) tcp_calloc(hset->func_handler->data_len);
    hset->func_handler->sin_size = sizeof(hset->func_handler->client_addr);
    hset->select_fds = (int*) tcp_calloc(hset->max_link);
    for (int i = 0; i < hset->max_link; selectfds[i] = 0, ++i);
    hset->select_fds = selectfds;
    while(1){
        //不可缺少的，缺少了有可能导致状态不会更新
        init_select(logt, hset);
        if (_select(logt, hset) > 0) {
            _select_loop(logt, hset);
            _conn_handler(logt, hset);
        }
    }
}

int Select(log_t *logt, struct tcp_socket_event_loop_s *hset) {
    _init_select(logt, hset);
    free(hset->select_fds);
}
#endif